package com.njtoyo.taxi.admin.logic.business.simple_call;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.njtoyo.taxi.admin.handler.FilterHandler;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.enums.SimpleCallRideCancellationTriggerBy;
import com.njtoyo.taxi.admin.mapper.master.enums.SimpleCallRideState;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.rest.presenter.business.simple_call_ride.ListPresenter;
import com.njtoyo.taxi.admin.rest.wrapper.business.simpleCallRide.SimpleCallRideQueryWrapper;
import com.njtoyo.taxi.entity.backend.AdminUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

@Service
@Slf4j
public class SimpleCallRideLogic {

    @Autowired
    private SimpleCallRideMapper simpleCallRideMapper;

    @Autowired
    private SimpleCallRideCancellationMapper simpleCallRideCancellationMapper;

    @Autowired
    private SimpleCallRideStateMapper simpleCallRideStateMapper;

    @Autowired
    private TaxiMapper taxiMapper;

    @Autowired
    private DriverMapper driverMapper;

    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private SimpleCallCustomerMapper simpleCallCustomerMapper;

    @Autowired
    private GeoCantonMapper geoCantonMapper;

    @Autowired
    private GeoAreaMapper geoAreaMapper;

    @Autowired
    private GeoCustomerRegionMapper geoCustomerRegionMapper;

    @Autowired
    private SimpleCallCancelReasonLogLogic simpleCallCancelReasonLogLogic;

    @Autowired
    private SimpleCallRideOrderLogic simpleCallRideOrderLogic;

    @Autowired
    private SimpleCallRideCancellationLogic simpleCallRideCancellationLogic;


    @Transactional
    public void cancel(SimpleCallRide ride) {
        // 添加取消记录
        SimpleCallRideCancellation cancellation = new SimpleCallRideCancellation();
        cancellation.setRideId(ride.getId())
                .setCustomerId(ride.getCustomerId())
                .setDriverId(ride.getDriverId())
                .setTriggerBy(SimpleCallRideCancellationTriggerBy.admin);
        simpleCallRideCancellationMapper.insert(cancellation);
        // 修改行程状态
        new LambdaUpdateChainWrapper<>(simpleCallRideMapper)
                .eq(SimpleCallRide::getId, ride.getId())
                .set(SimpleCallRide::getIsCancel, true)
                .set(SimpleCallRide::getIsFinished, true)
                .update();
        // 修改车俩状态
        new LambdaUpdateChainWrapper<>(taxiMapper)
                .eq(Taxi::getId, ride.getTaxiId())
                .set(Taxi::getIsAvailable, true)
                .update();
    }

    @Transactional
    public void cancelBy(SimpleCallRide ride, SimpleCallRideCancellationTriggerBy triggerBy) {
        // 添加取消记录
        SimpleCallRideCancellation cancellation = new SimpleCallRideCancellation();
        cancellation.setRideId(ride.getId())
                .setCustomerId(ride.getCustomerId())
                .setDriverId(ride.getDriverId())
                .setTriggerBy(triggerBy);
        simpleCallRideCancellationMapper.insert(cancellation);
        // 修改行程状态
        new LambdaUpdateChainWrapper<>(simpleCallRideMapper)
                .eq(SimpleCallRide::getId, ride.getId())
                .set(SimpleCallRide::getIsCancel, true)
                .set(SimpleCallRide::getIsFinished, true)
                .update();
        // 修改车俩状态
        new LambdaUpdateChainWrapper<>(taxiMapper)
                .eq(Taxi::getId, ride.getTaxiId())
                .set(Taxi::getIsAvailable, true)
                .update();
    }

    @Transactional
    public void start(SimpleCallRide ride) {
        Taxi taxi = taxiMapper.selectById(ride.getTaxiId());
        // 添加状态修改记录
        com.njtoyo.taxi.admin.mapper.master.entity.SimpleCallRideState state = new com.njtoyo.taxi.admin.mapper.master.entity.SimpleCallRideState();
        state.setRideId(ride.getId())
                .setState(SimpleCallRideState.start)
                .setLocate(taxi.getLastLocate());
        simpleCallRideStateMapper.insert(state);
        // 修改行程状态
        new LambdaUpdateChainWrapper<>(simpleCallRideMapper)
                .eq(SimpleCallRide::getId, ride.getId())
                .set(SimpleCallRide::getState, SimpleCallRideState.start)
                .set(SimpleCallRide::getContractedTimestamp, DateUtil.currentSeconds())
                .update();
    }

    // 根据司机搜索，获取SimpleCallIds
    public List<Long> getSimpleCallIdsByDriverSearch(String driverSearch) {
        LambdaQueryChainWrapper<SimpleCallRide> query = new LambdaQueryChainWrapper<>(simpleCallRideMapper);

        if (this.isPhoneNum(driverSearch)) {
            query.inSql(SimpleCallRide::getDriverId, String.format("SELECT id FROM driver WHERE mobile_number = '%s'", driverSearch));
        } else {
            query.inSql(SimpleCallRide::getDriverId, String.format("SELECT id FROM driver WHERE name LIKE '%%%s%%'", driverSearch));
        }

        List<SimpleCallRide> list = query.select(SimpleCallRide::getRefId).list();

        if (ObjectUtil.isNotEmpty(list)) {
            return list.stream().map(SimpleCallRide::getRefId).collect(toList());
        }

        return null;
    }

    private Boolean isPhoneNum(String content) {
        return ReUtil.isMatch("^1[0-9]\\d{9}$", content);
    }

    // 根据 simpleCallIds 获取行程数据
    public List<SimpleCallRide> selectRealOriginBySimpleCallIds(Set<Long> simpleCallIds) {
        return new LambdaQueryChainWrapper<>(simpleCallRideMapper)
                .in(SimpleCallRide::getRefId, simpleCallIds)
                .list();
    }

    // 电召行程，根据用户、筛选条件，构建 query
    public LambdaQueryChainWrapper<SimpleCallRide> getQueryForRideList(AdminUser adminUser, SimpleCallRideQueryWrapper queryWrapper) {
        List<Long> queryCantonIds = new ArrayList<>();
        List<Long> queryCompanyIds = new ArrayList<>();

        FilterHandler filterHandler = new FilterHandler(adminUser, queryWrapper.getCantonId(), queryWrapper.getCompanyId());
        switch (adminUser.getAccountType()) {
            case canton:
                List<Long> cantonIds = filterHandler.getCantonIds();
                if (ObjectUtil.isNotEmpty(cantonIds)) {
                    queryCantonIds.addAll(cantonIds);
                }
                break;
            case company:
                List<Long> companyIds = filterHandler.getCompanyIds();
                if (ObjectUtil.isNotEmpty(companyIds)) {
                    queryCompanyIds.addAll(companyIds);
                }
                break;
        }

        LambdaQueryChainWrapper<SimpleCallRide> query = new LambdaQueryChainWrapper<>(simpleCallRideMapper);

        // 电召、一键叫车
        query.eq(Objects.nonNull(queryWrapper.getCategory()), SimpleCallRide::getCategory, queryWrapper.getCategory());
        query.in(Objects.nonNull(queryWrapper.getCategoryList()), SimpleCallRide::getCategory, queryWrapper.getCategoryList());

        // 1. 行政区
        if (ObjectUtil.isNotEmpty(queryWrapper.getCantonId())) {
            queryCantonIds.add(queryWrapper.getCantonId());
        }
        query.in(ObjectUtil.isNotEmpty(queryCantonIds), SimpleCallRide::getCantonId, queryCantonIds);

        // 2. 公司
        if (ObjectUtil.isNotEmpty(queryWrapper.getCompanyId())) {
            queryCompanyIds.add(queryWrapper.getCompanyId());
        }
        query.in(ObjectUtil.isNotEmpty(queryCompanyIds), SimpleCallRide::getCompanyId, queryCompanyIds);

        // 3. 乘客搜索
        String customerSearch = queryWrapper.getCustomerSearch();
        if (ObjectUtil.isNotEmpty(customerSearch)) {
            if (this.isPhoneNum(customerSearch)) {
                query.inSql(SimpleCallRide::getCustomerId, String.format("SELECT id FROM simple_call_customer WHERE mobile_number = '%s'", customerSearch));
            } else {
                query.inSql(SimpleCallRide::getCustomerId, String.format("SELECT id FROM simple_call_customer WHERE name LIKE '%%%s%%'", customerSearch));
            }
        }
        query.eq(ObjectUtil.isNotEmpty(queryWrapper.getCustomerId()), SimpleCallRide::getCustomerId, queryWrapper.getCustomerId());

        // 4. 司机搜索
        String driverSearch = queryWrapper.getDriverSearch();
        if (ObjectUtil.isNotEmpty(driverSearch)) {
            if (this.isPhoneNum(driverSearch)) {
                query.inSql(SimpleCallRide::getDriverId, String.format("SELECT id FROM driver WHERE mobile_number = '%s'", driverSearch));
            } else {
                query.inSql(SimpleCallRide::getDriverId, String.format("SELECT id FROM driver WHERE name LIKE '%%%s%%'", driverSearch));
            }
        }
        query.eq(ObjectUtil.isNotEmpty(queryWrapper.getDriverId()), SimpleCallRide::getDriverId, queryWrapper.getDriverId());

        // 5. 是否结束
        query.eq(ObjectUtil.isNotEmpty(queryWrapper.getIsFinished()), SimpleCallRide::getIsFinished, queryWrapper.getIsFinished());

        // 6. 是否取消
        query.eq(ObjectUtil.isNotEmpty(queryWrapper.getIsCancel()), SimpleCallRide::getIsCancel, queryWrapper.getIsCancel());

        // 7. 行程id
        query.eq(ObjectUtil.isNotEmpty(queryWrapper.getRideId()), SimpleCallRide::getId, queryWrapper.getRideId());

        // 8. 开始、结束时间
        if (ObjectUtil.isNotEmpty(queryWrapper.getStartDate()) && ObjectUtil.isNotEmpty(queryWrapper.getEndDate())) {
            query.between(SimpleCallRide::getCreatedAt, DateUtil.beginOfDay(queryWrapper.getStartDate()), DateUtil.endOfDay(queryWrapper.getEndDate()));
        }

        return query;
    }

    // 转换分页数据结果
    public List<ListPresenter> convertRideQueryList(List<SimpleCallRide> recordList) {
        Set<Long> simpleCallIds = new HashSet<>();
        Set<Long> customerIds = new HashSet<>();
        Set<Long> cantonIds = new HashSet<>();
        Set<Long> areaIds = new HashSet<>();

        Set<Long> driverIds = new HashSet<>();
        Set<Long> companyIds = new HashSet<>();
        Set<Long> taxiIds = new HashSet<>();

        Set<Long> callRegionIds = new HashSet<>();
        Set<Long> rideIds = new HashSet<>();

        recordList.forEach(ride -> {
            simpleCallIds.add(ride.getRefId());
            customerIds.add(ride.getCustomerId());
            cantonIds.add(ride.getCantonId());
            areaIds.add(ride.getAreaId());

            driverIds.add(ride.getDriverId());
            companyIds.add(ride.getCompanyId());
            taxiIds.add(ride.getTaxiId());

            callRegionIds.add(ride.getCallRegionId());
            rideIds.add(ride.getId());
        });

        Map<Long, Driver> driverMap = new HashMap<>();
        Map<Long, String> companyMap = new HashMap<>();
        Map<Long, String> taxiMap = new HashMap<>();
        Map<Long, SimpleCallCustomer> customerMap = new HashMap<>();
        Map<Long, String> cantonMap = new HashMap<>();
        Map<Long, String> areaMap = new HashMap<>();
        Map<Long, String> callRegionMap = new HashMap<>();
        Map<Long, String> cancelReasonLogMap = new HashMap<>();

        // rideId => i
        Map<Long, SimpleCallRideOrder> rideOrderMap = new HashMap<>();

        // rideId => trigger_by
        Map<Long, SimpleCallRideCancellationTriggerBy> rideCancellationMap = new HashMap<>();

        // 1. 查司机
        if (ObjectUtil.isNotEmpty(driverIds)) {
            List<Driver> driverList = driverMapper.selectBatchIds(driverIds);
            driverMap = driverList.stream().collect(Collectors.toMap(Driver::getId, i -> i));
        }

        // 2. 查公司
        if (ObjectUtil.isNotEmpty(companyIds)) {
            List<Company> companyList = companyMapper.selectBatchIds(companyIds);
            companyMap = companyList.stream().collect(Collectors.toMap(Company::getId, Company::getName));
        }

        // 3. 查车辆
        if (ObjectUtil.isNotEmpty(taxiIds)) {
            List<Taxi> taxiList = taxiMapper.selectBatchIds(taxiIds);
            taxiMap = taxiList.stream().collect(Collectors.toMap(Taxi::getId, Taxi::getPlateNumber));
        }

        // 4. 查乘客
        if (ObjectUtil.isNotEmpty(customerIds)) {
            List<SimpleCallCustomer> customerList = simpleCallCustomerMapper.selectBatchIds(customerIds);
            if (ObjectUtil.isNotEmpty(customerList)) {
                customerMap = customerList.stream().collect(Collectors.toMap(SimpleCallCustomer::getId, i -> i));
            }
        }

        // 5. 查 canton
        if (ObjectUtil.isNotEmpty(cantonIds)) {
            List<GeoCanton> cantonList = geoCantonMapper.selectBatchIds(cantonIds);
            if (ObjectUtil.isNotEmpty(cantonList)) {
                cantonMap = cantonList.stream().collect(Collectors.toMap(GeoCanton::getId, GeoCanton::getName));
            }
        }

        // 6. 查 area
        if (ObjectUtil.isNotEmpty(areaIds)) {
            List<GeoArea> areaList = geoAreaMapper.selectBatchIds(areaIds);
            if (ObjectUtil.isNotEmpty(areaList)) {
                areaMap = areaList.stream().collect(Collectors.toMap(GeoArea::getId, GeoArea::getName));
            }
        }

        // 7. 查 geo_customer_region
        if (ObjectUtil.isNotEmpty(callRegionIds)) {
            List<GeoCustomerRegion> callRegionList = geoCustomerRegionMapper.selectBatchIds(callRegionIds);
            if (ObjectUtil.isNotEmpty(callRegionList)) {
                callRegionMap = callRegionList.stream().collect(Collectors.toMap(GeoCustomerRegion::getId, GeoCustomerRegion::getName));
            }
        }

        // 8. 查 simple_call_cancel_reason_log
        List<SimpleCallCancelReasonLog> cancelReasonLogList = simpleCallCancelReasonLogLogic.selectByRideIds(rideIds);
        if (ObjectUtil.isNotEmpty(cancelReasonLogList)) {
            cancelReasonLogMap = cancelReasonLogList.stream().collect(Collectors.toMap(SimpleCallCancelReasonLog::getRideId, SimpleCallCancelReasonLog::getReason));
        }

        // 9. simple_call_ride_order
        List<SimpleCallRideOrder> rideOrderList = simpleCallRideOrderLogic.selectByRideIds(rideIds);
        if (ObjectUtil.isNotEmpty(rideOrderList)) {
            rideOrderMap = rideOrderList.stream().collect(Collectors.toMap(SimpleCallRideOrder::getRideId, i -> i));
        }

        // 10. simple_call_ride_cancellation
        List<SimpleCallRideCancellation> rideCancellationList = simpleCallRideCancellationLogic.selectByRideIds(rideIds);
        if (ObjectUtil.isNotEmpty(rideCancellationList)) {
            rideCancellationMap =  rideCancellationList.stream()
                    .collect(Collectors.toMap(
                            SimpleCallRideCancellation::getRideId,
                            SimpleCallRideCancellation::getTriggerBy,
                            (existing, replacement) -> existing));
        }

        Map<Long, SimpleCallCustomer> finalCustomerMap = customerMap;
        Map<Long, Driver> finalDriverMap = driverMap;
        Map<Long, String> finalCompanyMap = companyMap;
        Map<Long, String> finalTaxiMap = taxiMap;
        Map<Long, String> finalCantonMap = cantonMap;
        Map<Long, String> finalAreaMap = areaMap;
        Map<Long, String> finalCallRegionMap = callRegionMap;
        Map<Long, String> finalCancelReasonLogMap = cancelReasonLogMap;
        Map<Long, SimpleCallRideOrder> finalRideOrderMap = rideOrderMap;
        Map<Long, SimpleCallRideCancellationTriggerBy> finalRideCancellationMap = rideCancellationMap;
        List<ListPresenter> res = new ArrayList<>();

        recordList.forEach(i -> {
            ListPresenter response = new ListPresenter();
            response.setId(i.getId());
            response.setCreatedAt(i.getCreatedAt());
            response.setState(i.getState());
            response.setIsCancel(i.getIsCancel());
            response.setCategory(i.getCategory());

            response.setIsFinished(i.getIsFinished());
            response.setOriginName(i.getOriginName());
            response.setOriginPlaceName(i.getOriginPlaceName());
            response.setRealOriginName(i.getRealOriginName());
            response.setRealOriginPlaceName(i.getRealOriginPlaceName());
            response.setDestinationName(i.getDestinationName());
            response.setDestinationPlaceName(i.getDestinationPlaceName());

            // 设置 simple_call_customer
            SimpleCallCustomer itemCustomer = finalCustomerMap.get(i.getCustomerId());
            if (ObjectUtil.isNotEmpty(itemCustomer)) {
                response.setCustomerId(itemCustomer.getId());
                response.setCustomerName(itemCustomer.getName());
                response.setCustomerMobileNumber(itemCustomer.getMobileNumber());
            }

            // 设置 司机
            Driver itemDriver = finalDriverMap.get(i.getDriverId());
            if (ObjectUtil.isNotEmpty(itemDriver)) {
                response.setDriverId(itemDriver.getId());
                response.setDriverName(itemDriver.getName());
                response.setDriverMobileNumber(itemDriver.getMobileNumber());
            }

            // 设置公司
            String itemCompanyName = finalCompanyMap.get(i.getCompanyId());
            if (ObjectUtil.isNotEmpty(itemCompanyName)) {
                response.setCompanyId(i.getCompanyId());
                response.setCompanyName(itemCompanyName);
            }

            // 设置车辆
            String itemTaxiPlateNumber = finalTaxiMap.get(i.getTaxiId());
            if (ObjectUtil.isNotEmpty(itemTaxiPlateNumber)) {
                response.setTaxiId(i.getTaxiId());
                response.setTaxiPlateNumber(itemTaxiPlateNumber);
            }

            // 设置 geo_canton
            String itemCantonName = finalCantonMap.get(i.getCantonId());
            if (ObjectUtil.isNotEmpty(itemCantonName)) {
                response.setCantonId(i.getCantonId());
                response.setCantonName(itemCantonName);
            }

            // 设置 areaMap
            String itemAreaName = finalAreaMap.get(i.getAreaId());
            if (ObjectUtil.isNotEmpty(itemAreaName)) {
                response.setAreaId(i.getAreaId());
                response.setAreaName(itemAreaName);
            }

            // 设置 geo_customer_region
            String itemCallRegionName = finalCallRegionMap.get(i.getCallRegionId());
            if (ObjectUtil.isNotEmpty(itemCallRegionName)) {
                response.setCallRegionId(i.getCallRegionId());
                response.setCallRegionName(itemCallRegionName);
            }

            // 设置 simple_call_cancel_reason_log
            String itemCancelReason = finalCancelReasonLogMap.get(i.getId());
            if (ObjectUtil.isNotEmpty(itemCancelReason)) {
                response.setCancelId(i.getId());
                response.setCancelReason(itemCancelReason);
            }

            // 设置 simple_call_ride_order
            SimpleCallRideOrder itemRideOrder = finalRideOrderMap.get(i.getId());
            if (ObjectUtil.isNotEmpty(itemRideOrder)) {
                response.setAmount(itemRideOrder.getAmount());
                response.setIsPaid(itemRideOrder.getIsPaid());
                response.setPaidTimestamp(itemRideOrder.getPaidTimestamp());
                response.setIsOnline(itemRideOrder.getIsOnline());
                response.setPaymentChannel(itemRideOrder.getPaymentChannel());
            }

            // 设置 simple_call_ride_cancellation
            SimpleCallRideCancellationTriggerBy itemRideCancellation = finalRideCancellationMap.get(i.getId());
            if (ObjectUtil.isNotEmpty(itemRideCancellation)) {
                response.setTriggerBy(itemRideCancellation);
            }

            res.add(response);
        });

        return res;
    }

    // 判断行程是否有未付款的订单
    public SimpleCallRideOrder getUnpaidOrderByRideId(Long rideId) {
        SimpleCallRideOrder rideOrder = simpleCallRideOrderLogic.getOneRideOrderByRideId(rideId);

        if (Objects.nonNull(rideOrder) && !rideOrder.getIsPaid()) {
            return rideOrder;
        }

        return null;
    }

    /**
     * 修改指定ride的state
     */
    public boolean onlineOrderSetOffline(Long rideId) {
        return new LambdaUpdateChainWrapper<>(simpleCallRideMapper)
                .eq(SimpleCallRide::getId, rideId)
                .set(SimpleCallRide::getState, SimpleCallRideState.end)
                .set(SimpleCallRide::getIsFinished, true)
                .set(SimpleCallRide::getUpdatedAt, new Date())
                .update();
    }


    @Transactional
    public void cancelByType(SimpleCallRide ride, SimpleCallRideCancellationTriggerBy triggerBy) {
        // 添加取消记录
        SimpleCallRideCancellation cancellation = new SimpleCallRideCancellation();
        cancellation.setRideId(ride.getId())
                .setCustomerId(ride.getCustomerId())
                .setDriverId(ride.getDriverId())
                .setTriggerBy(triggerBy);
        simpleCallRideCancellationMapper.insert(cancellation);
        // 修改行程状态
        new LambdaUpdateChainWrapper<>(simpleCallRideMapper)
                .eq(SimpleCallRide::getId, ride.getId())
                .set(SimpleCallRide::getIsCancel, true)
                .set(SimpleCallRide::getIsFinished, true)
                .update();
        // 修改车俩状态
        new LambdaUpdateChainWrapper<>(taxiMapper)
                .eq(Taxi::getId, ride.getTaxiId())
                .set(Taxi::getIsAvailable, true)
                .update();
    }
}
